// a simple synchronized fifo, implement with dpdistram
module syn_fifo #(
  parameter DEPTH = 4,
  parameter WIDTH = 32
) (
  input clk,
  input rst,
  input flush,

  // write port
  input             wvalid,
  output            wready,
  input [WIDTH-1:0] wdata ,

  // read port
  output rvalid,
  input  rready,
  output [WIDTH-1:0] rdata
);
  // when the most signidicant bit of head and tail are equal,
  // the fifo might be empty, or it might be full.
  reg [$clog2(DEPTH):0] head;
  reg [$clog2(DEPTH):0] tail;

  wire empty;
  wire full;
    
  assign empty = head == tail;
  assign full = (head[$clog2(DEPTH)] ^ tail[$clog2(DEPTH)]) && (head[$clog2(DEPTH)-1:0] == tail[$clog2(DEPTH)-1:0]);

  always@(posedge clk) begin
    if (rst || flush) begin
      head <= 0;
    end else if (rvalid && rready) begin
      head <= head + 1;
    end
  end

  always@(posedge clk) begin
    if (rst || flush) begin
      tail <= 0;
    end else if (wvalid && wready) begin
      tail <= tail + 1;
    end
  end

  dpdistram #(
    .WIDTH(WIDTH),
    .DEPTH(DEPTH)
  ) fifo (
    .clk(clk),
    .rst(rst),
    .wea(wvalid && wready),
    .ena(1'b1),
    .enb(1'b1),
    .addra(tail[$clog2(DEPTH)-1:0]),
    .addrb(head[$clog2(DEPTH)-1:0]),
    .dina(wdata),
    .douta(),
    .doutb(rdata)
  );

  assign wready = !full;
  assign rvalid = !empty;
  
endmodule